//    entity language compiler Copyright (C) 2011 Vincent Belliard

//    This program is free software: you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation version 3 of the License.

//    This program is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Public License for more details.

//    You should have received a copy of the GNU General Public License
//    along with this program.  If not, see <http://www.gnu.org/licenses/>.

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <typeinfo>
#include "types.h"
#include "entity.h"
#include "method.h"
#include "type.h"
#include "expression.h"
#include "object_class.h"
#include "scope.h"

// }{--------------------------------------------------------------

T_object_class_field::~T_object_class_field()
{
if (type != NULL) delete type ;
if (default_value != NULL) delete default_value ;
}

void T_object_class_field::dump(FILE *file) const
{
fprintf(file, "field %s", name.string()) ;
if (type != NULL)
	{
	fprintf(file, " : ") ;
	type->dump(file) ;
	}
if (default_value != NULL)
	{
	fprintf(file, " : default_value = ") ;
	default_value->dump(file) ;
	}
fprintf(file, " ;\n") ;
}

void T_object_class_field::parse(T_entity_compiler *compiler)
{
if (compiler->current_item != entity_compiler_item_colon)
	{
	compiler->add_error(compiler->location, "colon expected.") ;
	compiler->skip_semicolon() ;
	return ;
	}
compiler->next_item() ;
type = compiler->parse_type() ;
if (type == NULL)
	{
	compiler->add_error(compiler->location, "type expected.") ;
	compiler->skip_semicolon() ;
	return ;
	}
while (compiler->current_item == entity_compiler_item_colon)
	{
	compiler->next_item() ;
	if (compiler->parse_keyword("default_value"))
		{
		if (compiler->current_item != entity_compiler_item_equal)
			{
			compiler->add_error(compiler->location, "equal expected.") ;
			compiler->skip_colon() ;
			}
		else
			{
			compiler->next_item() ;
			default_value = compiler->parse_expression() ;
			if (default_value == NULL)
				{
				compiler->add_error(compiler->location, "expression expected.") ;
				compiler->skip_colon() ;
				}
			}
		}
	else if (compiler->parse_keyword("initial_value"))
		{
		value_fixed = TRUE ;
		if (compiler->current_item != entity_compiler_item_equal)
			{
			compiler->add_error(compiler->location, "equal expected.") ;
			compiler->skip_colon() ;
			}
		else
			{
			compiler->next_item() ;
			default_value = compiler->parse_expression() ;
			if (default_value == NULL)
				{
				compiler->add_error(compiler->location, "expression expected.") ;
				compiler->skip_colon() ;
				}
			}
		}
	else
		{
		compiler->add_error(compiler->location, "field attribute expected.") ;
		compiler->skip_colon() ;
		}
	}
if (compiler->current_item != entity_compiler_item_semicolon)
	{
	compiler->add_error(compiler->location, "semicolon expected.") ;
	compiler->skip_semicolon() ;
	return ;
	}
compiler->next_item() ;
}

void T_object_class_field::verify_type_semantic(T_entity_compiler *compiler, T_entity_program *program, T_scope *scope)
{
type->verify_semantic(compiler, program, scope, NULL) ;
}

void T_object_class_field::verify_semantic(T_entity_compiler *compiler, T_entity_program *program, T_scope *scope)
{
}

void T_object_class_field::generate_declaration(FILE *file)
{
fprintf(file, "\t") ;
type->generate_type_name(file, type_generate_value) ;
fprintf(file, " _%s ;\n", name.string()) ;
}

// }{--------------------------------------------------------------

void T_constructor::dump(FILE *file) const
{
fprintf(file, "constructor") ;
prototype.dump(file) ;
fprintf(file, " : ") ;
if (expression != NULL) expression->dump(file) ;
fprintf(file, " ;\n") ;
}

void T_constructor::parse(T_entity_compiler *compiler)
{
if (!prototype.parse(compiler))
	{
	compiler->skip_semicolon() ;
	}
else
	{
	compiler->parse_colon() ;
	if (native)
		{
		T_entity_location where(compiler->file_name, compiler->location) ;
		T_expression_native *loc = new T_expression_native(where, expression_native_entity) ;
		loc->parse(compiler) ;
		expression = loc ;
		}
	else if (native_cpp)
		{
		T_entity_location where(compiler->file_name, compiler->location) ;
		T_expression_native *loc = new T_expression_native(where, expression_native_cpp) ;
		loc->parse(compiler) ;
		expression = loc ;
		}
	else
		{
		expression = compiler->parse_expression() ;
		}
	if (expression == NULL)
		{
		compiler->add_error(compiler->location, "expression expected.") ;
		compiler->skip_semicolon() ;
		}
	}
if (compiler->current_item == entity_compiler_item_semicolon)
	{
	compiler->next_item() ;
	return ;
	}
if ((expression != NULL) && expression->is_block()) return ;
compiler->add_error(compiler->location, "semicolon expected.") ;
compiler->skip_semicolon() ;
}

int T_constructor::is_good_for_constructor(T_entity_program *program, T_expression_constructor_arguments *constructor) const
{
return prototype.is_good_for_constructor(program, constructor) ;
}

void T_constructor::verify_type_semantic(T_entity_compiler *compiler, T_entity_program *program, T_scope *scope)
{
prototype.verify_semantic(compiler, program, scope, NULL, object_class) ;
}

void T_constructor::verify_semantic(T_entity_compiler *compiler, T_entity_program *program, T_scope *scope)
{
T_object_class_constructor_scope scope_loc(scope, this) ;
expression->verify_semantic(compiler, program, &scope_loc, NULL) ;
}

void T_constructor::generate_prototype(FILE *file)
{
fprintf(file, "void constructor_%p", this) ;
prototype.generate_prototype(file, true) ;
}

void T_constructor::generate_method(T_entity_program *program, FILE *file)
{
if (expression != NULL)
	{
	generate_prototype(file) ;
	fprintf(file, "\n") ;
	expression->prepare(program, file) ;
	expression->generate_instruction(program, file) ;
	}
}

// }{--------------------------------------------------------------

void T_starter::dump(FILE *file) const
{
fprintf(file, "starter") ;
prototype.dump(file) ;
fprintf(file, " : ") ;
if (expression != NULL) expression->dump(file) ;
fprintf(file, " ;\n") ;
}

void T_starter::parse(T_entity_compiler *compiler)
{
if (!prototype.parse(compiler))
	{
	compiler->skip_semicolon() ;
	}
else
	{
	compiler->parse_colon() ;
	if (native)
		{
		T_entity_location where(compiler->file_name, compiler->location) ;
		T_expression_native *loc = new T_expression_native(where, expression_native_entity) ;
		loc->parse(compiler) ;
		expression = loc ;
		}
	else if (native_cpp)
		{
		T_entity_location where(compiler->file_name, compiler->location) ;
		T_expression_native *loc = new T_expression_native(where, expression_native_cpp) ;
		loc->parse(compiler) ;
		expression = loc ;
		}
	else
		{
		expression = compiler->parse_expression() ;
		}
	if (expression == NULL)
		{
		compiler->add_error(compiler->location, "expression expected.") ;
		compiler->skip_semicolon() ;
		}
	}
if (compiler->current_item != entity_compiler_item_semicolon)
	{
	compiler->add_error(compiler->location, "semicolon expected.") ;
	compiler->skip_semicolon() ;
	return ;
	}
compiler->next_item() ;
}

// }{--------------------------------------------------------------

void T_destructor::dump(FILE *file) const
{
fprintf(file, "destructor") ;
fprintf(file, " : ") ;
if (expression != NULL) expression->dump(file) ;
fprintf(file, " ;\n") ;
}

void T_destructor::parse(T_entity_compiler *compiler)
{
compiler->parse_colon() ;
if (native)
	{
	T_entity_location where(compiler->file_name, compiler->location) ;
	T_expression_native *loc = new T_expression_native(where, expression_native_entity) ;
	loc->parse(compiler) ;
	expression = loc ;
	}
else if (native_cpp)
	{
	T_entity_location where(compiler->file_name, compiler->location) ;
	T_expression_native *loc = new T_expression_native(where, expression_native_cpp) ;
	loc->parse(compiler) ;
	expression = loc ;
	}
else
	{
	expression = compiler->parse_expression() ;
	}
if (expression == NULL)
	{
	compiler->add_error(compiler->location, "expression expected.") ;
	compiler->skip_semicolon() ;
	}
if (compiler->current_item != entity_compiler_item_semicolon)
	{
	compiler->add_error(compiler->location, "semicolon expected.") ;
	compiler->skip_semicolon() ;
	return ;
	}
compiler->next_item() ;
}

// }{--------------------------------------------------------------

void T_object_class_method::dump(FILE *file) const
{
fprintf(file, "method %s", name.string()) ;
type->dump_content(file) ;
fprintf(file, " : ") ;
if (expression != NULL) expression->dump(file) ;
fprintf(file, " ;\n") ;
}

void T_object_class_method::parse(T_entity_compiler *compiler, int new_test)
{
type = new T_type_method(location, new_test) ;
if (!type->parse(compiler))
	{
	compiler->skip_semicolon() ;
	return ;
	}
if (compiler->current_item == entity_compiler_item_semicolon)
	{
	compiler->next_item() ;
	return ;
	}
compiler->parse_colon() ;
if (native)
	{
	T_entity_location where(compiler->file_name, compiler->location) ;
	T_expression_native *loc = new T_expression_native(where, expression_native_entity) ;
	loc->parse(compiler) ;
	expression = loc ;
	}
else if (native_cpp)
	{
	T_entity_location where(compiler->file_name, compiler->location) ;
	T_expression_native *loc = new T_expression_native(where, expression_native_cpp) ;
	loc->parse(compiler) ;
	expression = loc ;
	}
else
	{
	expression = compiler->parse_expression() ;
	}
if (expression == NULL)
	{
	compiler->add_error(compiler->location, "expression expected.") ;
	compiler->skip_semicolon() ;
	return ;
	}
if (compiler->current_item == entity_compiler_item_semicolon)
	{
	compiler->next_item() ;
	}
else if (!expression->is_block())
	{
	compiler->add_error(compiler->location, "semicolon expected.") ;
	compiler->skip_semicolon() ;
	}
//compiler->add_error(compiler->location, "end func.") ;
}

void T_object_class_method::parse_operator(T_entity_compiler *compiler)
{
type = new T_type_method(location, FALSE) ;
for(;;)
	{
	if (compiler->current_item == entity_compiler_item_left_parenthesis)
		{
		if (!type->parse(compiler))
			{
			compiler->skip_semicolon() ;
			return ;
			}
		}
	else if (compiler->current_item == entity_compiler_item_semicolon)
		{
		compiler->next_item() ;
		return ;
		}
	else if (compiler->current_item == entity_compiler_item_colon)
		{
		break ;
		}
	else if (compiler->current_item == entity_compiler_item_eof)
		{
		return ;
		}
	else
		{
		compiler->next_item() ;
		}
	}
for(;;)
	{
	compiler->parse_colon() ;
	if (compiler->parse_keyword("priority"))
		{
		compiler->next_item() ;
		compiler->parse_expression() ;
		}
	else if (compiler->parse_keyword("associative"))
		{
		compiler->next_item() ;
		compiler->parse_expression() ;
		}
	else
		{
		break ;
		}
	}
if (native)
	{
	T_entity_location where(compiler->file_name, compiler->location) ;
	T_expression_native *loc = new T_expression_native(where, expression_native_entity) ;
	loc->parse(compiler) ;
	expression = loc ;
	}
else if (native_cpp)
	{
	T_entity_location where(compiler->file_name, compiler->location) ;
	T_expression_native *loc = new T_expression_native(where, expression_native_cpp) ;
	loc->parse(compiler) ;
	expression = loc ;
	}
else
	{
	expression = compiler->parse_expression() ;
	}
if (expression == NULL)
	{
	compiler->add_error(compiler->location, "expression expected.") ;
	compiler->skip_semicolon() ;
	return ;
	}
if (compiler->current_item == entity_compiler_item_semicolon)
	{
	compiler->next_item() ;
	}
else if (!expression->is_block())
	{
	compiler->add_error(compiler->location, "semicolon expected.") ;
	compiler->skip_semicolon() ;
	}
//compiler->add_error(compiler->location, "end func.") ;
}

int T_object_class_method::can_overload(const T_object_class_method *ref) const
{
//fprintf(stderr, "can %s.%s (overload=%d) overload %s.%s\n", object_class->name.string(), name.string(), ref->overload, ref->object_class->name.string(), ref->name.string()) ;
if (ref->overload) return FALSE ;
if (strcmp(name.string(), ref->name.string()) != 0) return FALSE ;
return type->can_overload(ref->type) ;
}

int T_object_class_method::is_good_for_call(T_entity_program *program, const T_string call_name, T_expression_constructor_arguments *call) const
{
//fprintf(stderr, "try %s (overload=%d)\n", name.string(), overload) ;
if (overload) return FALSE ;
if (strcmp(name.string(), call_name.string()) != 0) return FALSE ;
return type->is_good_for_call(program, call) ;
}

void T_object_class_method::verify_type_semantic(T_entity_compiler *compiler, T_entity_program *program, T_scope *scope)
{
type->verify_semantic(compiler, program, scope, NULL, object_class) ;
}

void T_object_class_method::verify_semantic(T_entity_compiler *compiler, T_entity_program *program, T_scope *scope)
{
T_object_class_method_scope scope_loc(scope, this) ;
if ((expression != NULL) && expression->verify_semantic(compiler, program, &scope_loc, type) && !expression->dead)
	{
	compiler->can_assign_to(expression->type, type->returned_type) ;
	}
}

void T_object_class_method::generate_virtual_field(FILE *file)
{
fprintf(file, "\t") ;
if (type->test) fprintf(file, "int") ;
else type->returned_type->generate_type_name(file, type_generate_value) ;
fprintf(file, " (*virtual_%s__%s)", object_class->name.string(), name.string()) ;
type->prototype.generate_prototype(file, TRUE) ;
fprintf(file, " ;\n") ;
}

void T_object_class_method::generate_cast(FILE *file)
{
fprintf(file, "(") ;
if (type->test) fprintf(file, "int") ;
else type->returned_type->generate_type_name(file, type_generate_value) ;
fprintf(file, " (*)") ;
type->prototype.generate_prototype(file, TRUE) ;
fprintf(file, ")") ;
}

void T_object_class_method::generate_prototype(FILE *file)
{
if (type->test) fprintf(file, "int") ;
else type->returned_type->generate_type_name(file, type_generate_value) ;
fprintf(file, " _%s__%s", object_class->name.string(), name.string()) ;
type->prototype.generate_prototype(file, TRUE) ;
}

void T_object_class_method::generate_method(T_entity_program *program, FILE *file)
{
if (expression != NULL)
	{
	generate_prototype(file) ;
	fprintf(file, "\n") ;
	if (base_method == NULL)
		{
		if (type->test && !expression->is_native())
			{
			fprintf(file, "{\n") ;
			int index_true = program->get_next_index() ;
			int index_false = program->get_next_index() ;
			expression->prepare(program, file) ;
			expression->generate_test(program, file, TRUE, index_true, index_false) ;
			fprintf(file, "label_%d: return FALSE ;\n", index_false) ;
			fprintf(file, "label_%d: return TRUE ;\n", index_true) ;
			fprintf(file, "}\n") ;
			}
		else
			{
			expression->prepare(program, file) ;
			expression->generate_instruction(program, file) ;
			}
		}
	else
		{
		int specialization_generated = FALSE ;
		T_object_class_method *main = NULL ;
		T_object_class *loc = object_class ;
		while (loc != NULL)
			{
			T_object_class_method *method = loc->methods.first ;
			while (method != NULL)
				{
				if (method->base_method == base_method)
					{
					if (method->type->specialization())
						{
						if (!specialization_generated)
							{
							specialization_generated = TRUE ;
							fprintf(file, "{\n") ;
							int index = program->get_next_index() ;
							method->type->prototype.generate_specialization(program, file, index) ;
							method->expression->prepare(program, file) ;
							method->expression->generate_instruction(program, file) ;
							if (!method->expression->dead) fprintf(file, "return ;\n") ;
							fprintf(file, "label_%d:;\n", index) ;
							}
						}
					else if (main == NULL)
						{
						main = method ;
						}
					}
				method = method->next ;
				}
			if ((loc->base_type == NULL) || (loc->base_type->get_class() != class_type_identifier)) break ;
			loc = ((T_type_identifier *)loc->base_type)->object_class ;
			}
		if (main != NULL)
			{
			if (type->test && !expression->is_native())
				{
				fprintf(file, "{\n") ;
				int index_true = program->get_next_index() ;
				int index_false = program->get_next_index() ;
				main->expression->prepare(program, file) ;
				main->expression->generate_test(program, file, TRUE, index_true, index_false) ;
				fprintf(file, "label_%d: return FALSE ;\n", index_false) ;
				fprintf(file, "label_%d: return TRUE ;\n", index_true) ;
				fprintf(file, "}\n") ;
				}
			else
				{
				main->expression->prepare(program, file) ;
				main->expression->generate_instruction(program, file) ;
				}
			}
		if (specialization_generated) fprintf(file, "}\n") ;
		}
	}
}

// }{--------------------------------------------------------------

int object_class_is_good_for_call(const T_object_class *object_class, T_entity_program *program, const T_type *call_type)
{
//fprintf(stderr, "class %s (%p) is good for call %d\n", object_class->name.string(), object_class, call_type->get_class()) ;
if (call_type->get_class() != class_type_identifier) return FALSE ;
//fprintf(stderr, "class=%s(%p)\n", ((T_type_identifier *)call_type)->object_class->name.string(), ((T_type_identifier *)call_type)->object_class) ;
return ((T_type_identifier *)call_type)->object_class == object_class ;
}

void object_class_generate_argv(FILE *file, const T_string &name)
{
fprintf(file, "defined_%s++ ;\n", name.string()) ;
}

T_object_class::T_object_class(const T_entity_location &new_location)
	: location(new_location)
{
enum_class = FALSE ;
complement = FALSE ;
complement_base = NULL ;
destructor = NULL ;
semantic_state = semantic_state_not_done ;
generated = FALSE ;
native_cpp_string = NULL ;
native_cpp_string_body = NULL ;
native_cpp_instance_string = NULL ;
is_good_for_call = &object_class_is_good_for_call ;
generate_argv = &object_class_generate_argv ;
}

T_object_class::T_object_class(const T_entity_location &new_location, const T_string new_name)
	: location(new_location), name(new_name)
{
enum_class = FALSE ;
complement = FALSE ;
complement_base = NULL ;
destructor = NULL ;
semantic_state = semantic_state_not_done ;
generated = FALSE ;
native_cpp_string = NULL ;
native_cpp_string_body = NULL ;
native_cpp_instance_string = NULL ;
is_good_for_call = &object_class_is_good_for_call ;
}

T_object_class::~T_object_class()
{
if (destructor != NULL) delete destructor ;
}

void T_object_class::dump(FILE *file) const
{
fprintf(stderr, "class %s", name.string()) ;
if (base_type != NULL)
	{
	fprintf(stderr, " inherits ") ;
	base_type->dump(file) ;
	}
fprintf(file, "\n") ;
fprintf(file, "{\n") ;
T_object_class_field *field = fields.first ;
while (field != NULL)
	{
	field->dump(file) ;
	field = field->next ;
	}
T_constructor *constructor = constructors.first ;
while (constructor != NULL)
	{
	constructor->dump(file) ;
	constructor = constructor->next ;
	}
T_starter *starter = starters.first ;
while (starter != NULL)
	{
	starter->dump(file) ;
	starter = starter->next ;
	}
if (destructor != NULL) destructor->dump(file) ;
T_object_class_method *method = methods.first ;
while (method != NULL)
	{
	method->dump(file) ;
	method = method->next ;
	}
fprintf(file, "}\n") ;
}

void T_object_class::parse(T_entity_compiler *compiler, T_entity_program *program)
{
//fprintf(stderr, "parse class <%s> : %p\n", name.string(), this) ;
if (compiler->parse_keyword("inherits"))
	{
	base_type = compiler->parse_type() ;
	}
else if (compiler->current_item == entity_compiler_item_add_equal)
	{
	compiler->next_item() ;
	complement = TRUE ;
	}
else
	{
	base_type = new T_type_identifier(location, program->class_class) ;
	}
if (compiler->parse_left_brace())
	{
	for(;;)
		{
		if (compiler->is_eof())
			{
			compiler->add_error(location, "unexpected end of file in definition.") ;
			return ;
			}
		if (compiler->parse_right_brace()) return ;
		T_entity_location where(compiler->file_name, compiler->location) ;
		compiler->parse_keyword("extended") ;
		compiler->parse_keyword("private") ;
		compiler->parse_keyword("protected") ;
		compiler->parse_keyword("public") ;
		if (compiler->parse_keyword("and"))
			{
			compiler->parse_keyword("extended") ;
			compiler->parse_keyword("private") ;
			compiler->parse_keyword("protected") ;
			compiler->parse_keyword("public") ;
			compiler->parse_keyword("read") ;
			}
		compiler->parse_keyword("constant") ;
		if (compiler->parse_keyword("values"))
			{
			enum_class = TRUE ;
			parse_values(compiler) ;
			goto end ;
			}
		{
		int overload = FALSE ;
		int native = FALSE ;
		int native_cpp = FALSE ;
		if (compiler->parse_keyword("native"))
			{
			if (compiler->parse_keyword("cpp")) native_cpp = TRUE ;
			else native = TRUE ;
			}
		if (compiler->parse_keyword("field"))
			{
			if (compiler->is_identifier())
				{
				T_object_class_field *field = new T_object_class_field(where, overload, compiler->string) ;
				fields.insert(field) ;
				compiler->next_item() ;
				field->parse(compiler) ;
				}
			else
				{
				compiler->add_error(compiler->location, "field name expected.") ;
				}
			}
		else if (compiler->parse_keyword("constructor"))
			{
			T_constructor *constructor = new T_constructor(this, where, native, native_cpp) ;
			constructors.insert(constructor) ;
			constructor->parse(compiler) ;
			}
		else if (compiler->parse_keyword("starter"))
			{
			T_starter *starter = new T_starter(where, native, native_cpp) ;
			starters.insert(starter) ;
			starter->parse(compiler) ;
			}
		else if (compiler->parse_keyword("destructor"))
			{
			if (destructor != NULL)
				{
				compiler->add_error(where, "destructor already defined.") ;
				delete destructor ;
				}
			destructor = new T_destructor(where, native, native_cpp) ;
			destructor->parse(compiler) ;
			}
		else if (compiler->parse_keyword("method"))
			{
			if (compiler->parse_keyword("overloads")) overload = TRUE ;
			if (compiler->is_identifier())
				{
				T_object_class_method *method = new T_object_class_method(this, where, overload, native, native_cpp, compiler->string) ;
				methods.insert(method) ;
				compiler->next_item() ;
				method->parse(compiler, FALSE) ;
				}
			else
				{
				compiler->add_error(compiler->location, "method name expected.") ;
				}
			}
		else if (compiler->parse_keyword("operator"))
			{
			T_object_class_method *method = new T_object_class_method(this, where, overload, native, native_cpp, "xxx") ;
			method->parse_operator(compiler) ;
			}
		else if (compiler->parse_keyword("test"))
			{
			if (!compiler->parse_keyword("method")) compiler->add_error(compiler->location, "Keyword method expected.") ;
			if (compiler->parse_keyword("overloads")) overload = TRUE ;
			if (compiler->is_identifier())
				{
				T_object_class_method *method = new T_object_class_method(this, where, overload, native, native_cpp, compiler->string) ;
				methods.insert(method) ;
				compiler->next_item() ;
				method->parse(compiler, TRUE) ;
				}
			else
				{
				compiler->add_error(compiler->location, "method name expected.") ;
				}
			}
		else
			{
			compiler->add_error(compiler->location, "class definition expected.") ;
			compiler->skip_semicolon() ;
			}
		}
end:;
		}
	}
else
	{
	compiler->add_error(compiler->location, "left brace expected.") ;
	compiler->skip_semicolon() ;
	}
}

void T_object_class::parse_values(T_entity_compiler *compiler)
{
compiler->parse_colon() ;
for(;;)
	{
	if (compiler->current_item == entity_compiler_item_semicolon)
		{
		compiler->next_item() ;
		return ;
		}
	if (compiler->current_item != entity_compiler_item_identifier)
		{
		compiler->add_error(compiler->location, "enum value ou semicolon expected.") ;
		compiler->skip_semicolon() ;
		return ;
		}
	values.insert(new T_object_class_value(this, compiler->string)) ;
	compiler->next_item() ;
	if (compiler->current_item != entity_compiler_item_comma)
		{
		if (compiler->current_item == entity_compiler_item_semicolon)
			{
			compiler->next_item() ;
			return ;
			}
		compiler->add_error(compiler->location, "semicolon or comma expected.") ;
		compiler->skip_semicolon() ;
		return ;
		}
	compiler->next_item() ;
	}
}

T_object_class_value *T_object_class::search_value(const T_string value_name) const
{
T_object_class_value *value = values.first ;
while (value != NULL)
	{
	if (strcmp(value->name.string(), value_name.string()) == 0) return value ;
	value = value->next ;
	}
return NULL ;
}

T_object_class_method *T_object_class::search_base_method_use(T_object_class_method *base) const
{
T_object_class_method *method = methods.first ;
while (method != NULL)
	{
	if (method->base_method == base) return method ;
	method = method->next ;
	}
return NULL ;
}

T_object_class_method *T_object_class::search_method_in_base(T_object_class_method *ref)
{
//fprintf(stderr, "search %s:%s\n", name.string(), ref->name.string()) ;
T_object_class *loc = this ;
for(;;)
	{
	T_object_class_method *method = loc->methods.first ;
	while (method != NULL)
		{
//fprintf(stderr, "compare with %s:%s\n", loc->name.string(), method->name.string()) ;
		if (ref->can_overload(method))
			{
			//fprintf(stderr, "overload OK\n") ;
			return method ;
			}
		//fprintf(stderr, "Can't overload\n") ;
		method = method->next ;
		}
	if (loc->base_type == NULL) return NULL ;
	if (loc->base_type->get_class() != class_type_identifier) return NULL ;
	loc = ((T_type_identifier *)loc->base_type)->object_class ;
	}
}

T_object_class_method *T_object_class::search_overload(T_object_class_method *ref)
{
//fprintf(stderr, "class %s search overload %s:%s\n", name.string(), ref->object_class->name.string(), ref->name.string()) ;
T_object_class *loc = this ;
for(;;)
	{
	T_object_class_method *method = loc->methods.first ;
	while (method != NULL)
		{
//fprintf(stderr, "cmp with %p %s:%s\n", method, method->object_class->name.string(), method->name.string()) ;
		if ((method->base_method == ref) || ((method == ref) && (method->expression != NULL))) return method ;
		method = method->next ;
		}
	if (loc->base_type == NULL) return NULL ;
	if (loc->base_type->get_class() != class_type_identifier) return NULL ;
	loc = ((T_type_identifier *)loc->base_type)->object_class ;
	}
}

const T_object_class_field *T_object_class::search_field(T_entity_program *program, const T_string name) const
{
const T_object_class *loc = this ;
for(;;)
	{
	if (loc == program->string_class)
		{
		if (strcmp(name.string(), "size") == 0)
			{
			T_object_class_field *loc = new T_object_class_field(location, FALSE, "size()") ;
			loc->type = new T_type_identifier(location, program->integer_32_class) ;
			return loc ;
			}
		if (strcmp(name.string(), "length") == 0)
			{
			T_object_class_field *loc = new T_object_class_field(location, FALSE, "length()") ;
			loc->type = new T_type_identifier(location, program->integer_32_class) ;
			return loc ;
			}
		}
	T_object_class_field *field = loc->fields.first ;
	while (field != NULL)
		{
		if (strcmp(field->name.string(), name.string()) == 0) return field ;
		field = field->next ;
		}
	if (loc->base_type == NULL) return NULL ;
	if (loc->base_type->get_class() != class_type_identifier) return NULL ;
	loc = ((T_type_identifier *)loc->base_type)->object_class ;
	}
}

int T_object_class::search_identifier(T_expression_identifier *expression, const T_string &name) const
{
const T_object_class *loc = this ;
for(;;)
	{
	T_object_class_field *field = loc->fields.first ;
	while (field != NULL)
		{
		if (strcmp(field->name.string(), name.string()) == 0)
			{
			expression->field = field ;
			expression->type = field->type ;
			return TRUE ;
			}
		field = field->next ;
		}
	if (loc->base_type == NULL) return FALSE ;
	if (loc->base_type->get_class() != class_type_identifier) return FALSE ;
	loc = ((T_type_identifier *)loc->base_type)->object_class ;
	}
}

const T_object_class_method *T_object_class::search_call(T_entity_program *program, const T_string method_name, T_expression_constructor_arguments *call) const
{
const T_object_class *loc = this ;
for(;;)
	{
//fprintf(stderr, "search in %s\n", name.string()) ;
	T_object_class_method *method = loc->methods.first ;
	while (method != NULL)
		{
		if (method->is_good_for_call(program, method_name, call)) return method ;
		method = method->next ;
		}
	if (loc->base_type == NULL) return NULL ;
	if (loc->base_type->get_class() != class_type_identifier) return NULL ;
	loc = ((T_type_identifier *)loc->base_type)->object_class ;
	}
}

const T_object_class_method *T_object_class::search_base_method(T_object_class_method *ref) const
{
const T_object_class *loc = this ;
for(;;)
	{
//fprintf(stderr, "search in %s\n", name.string()) ;
	T_object_class_method *method = loc->methods.first ;
	while (method != NULL)
		{
		if ((method == ref) || (method->base_method == ref)) return method ;
		method = method->next ;
		}
	if (loc->base_type == NULL) return NULL ;
	if (loc->base_type->get_class() != class_type_identifier) return NULL ;
	loc = ((T_type_identifier *)loc->base_type)->object_class ;
	}
}

const T_constructor *T_object_class::search_constructor(T_entity_program *program, T_expression_constructor_arguments *constructor)
{
//fprintf(stderr, "class %s %p : search_constructor\n", name.string(), this) ;
T_constructor *loc = constructors.first ;
while (loc != NULL)
	{
//fprintf(stderr, "try constructor %p\n", loc) ;
	if (loc->is_good_for_constructor(program, constructor)) return loc ;
	loc = loc->next ;
	}
return NULL ;
}

void T_object_class::use_complement(T_object_class *new_class)
{
{
T_constructor *constructor = new_class->constructors.first ;
while (constructor != NULL)
	{
	T_constructor *next = constructor->next ;
	new_class->constructors.remove(constructor) ;
	constructors.insert(constructor) ;
	constructor->object_class = this ;
	constructor = next ;
	}
}
{
T_object_class_method *method = new_class->methods.first ;
while (method != NULL)
	{
	T_object_class_method *next = method->next ;
	new_class->methods.remove(method) ;
	methods.insert(method) ;
	method->object_class = this ;
	method = next ;
	}
}
}

void T_object_class::verify_type_semantic(T_entity_compiler *compiler, T_entity_program *program, T_scope *scope)
{
if (base_type != NULL) base_type->verify_semantic(compiler, program, scope, NULL) ;
{
int next_value = 0 ;
T_object_class_value *value = values.first ;
while (value != NULL)
	{
	value->value = next_value++ ;
	value = value->next ;
	}
}
{
T_object_class_field *field = fields.first ;
while (field != NULL)
	{
	field->verify_type_semantic(compiler, program, scope) ;
	field = field->next ;
	}
}
{
T_constructor *constructor = constructors.first ;
while (constructor != NULL)
	{
	constructor->verify_type_semantic(compiler, program, scope) ;
	constructor = constructor->next ;
	}
}
{
T_object_class_method *method = methods.first ;
while (method != NULL)
	{
	method->verify_type_semantic(compiler, program, scope) ;
	method = method->next ;
	}
}
}

void T_object_class::verify_semantic(T_entity_compiler *compiler, T_entity_program *program, T_scope *scope)
{
if (base_type != NULL) base_type->verify_semantic(compiler, program, scope, NULL) ;
{
T_object_class_field *field = fields.first ;
while (field != NULL)
	{
	field->verify_semantic(compiler, program, scope) ;
	field = field->next ;
	}
}
{
T_constructor *constructor = constructors.first ;
while (constructor != NULL)
	{
	constructor->verify_semantic(compiler, program, scope) ;
	constructor = constructor->next ;
	}
}
{
T_object_class_method *method = methods.first ;
while (method != NULL)
	{
	method->verify_semantic(compiler, program, scope) ;
	method = method->next ;
	}
}
}

int T_object_class::verify_base_class_semantic(T_entity_compiler *compiler)
{
if (semantic_state == semantic_state_done) return TRUE ;
semantic_state = semantic_state_running ;
if ((base_type != NULL) && !base_type->verify_base_class_semantic(compiler))
	{
	compiler->add_error(base_type->location, "Recursive inheritance.") ;
	semantic_state = semantic_state_done ;
	return FALSE ;
	}
semantic_state = semantic_state_done ;
{
T_object_class_method *method = methods.first ;
while (method != NULL)
	{
	if (method->overload)
		{
		method->base_method = search_method_in_base(method) ;
		if (method->base_method == NULL) compiler->add_error(method->location, "base method not found.") ;
		else method->base_method->overloaded = TRUE ;
		}
	method = method->next ;
	}
}
return TRUE ;
}

void T_object_class::generate_names(FILE *file)
{
fprintf(file, "class CLASS_%s ;\n", name.string()) ;
fprintf(file, "class HEADER_%s ;\n", name.string()) ;
fprintf(file, "class INSTANCE_%s ;\n", name.string()) ;
}

void T_object_class::generate_class(FILE *file, T_entity_program *program)
{
fprintf(file, "class CLASS_%s", name.string()) ;
if (base_type != NULL)
	{
	fprintf(file, " : public ") ;
	base_type->generate_class_name(file) ;
	}
fprintf(file, "\n") ;
fprintf(file, "\t{\n") ;
fprintf(file, "public:\n") ;
if (strcmp(name.string(), "Entity_location") == 0) fprintf(file, "void operator=(CLASS_Entity_location &from) {if (&from != NULL) { _file_name = from._file_name ; _location = from._location ; } }\n") ;
if (enum_class)
	{
	fprintf(file, "int value ;\n") ;
	fprintf(file, "void operator=(int new_value) { value = new_value ; }\n") ;
	fprintf(file, "int operator==(int cmp) { return value == cmp ; }\n") ;
	fprintf(file, "int operator!=(int cmp) { return value != cmp ; }\n") ;
	fprintf(file, "int operator<=(int cmp) { return value <= cmp ; }\n") ;
	fprintf(file, "int operator>=(int cmp) { return value >= cmp ; }\n") ;
	fprintf(file, "int operator<(int cmp) { return value < cmp ; }\n") ;
	fprintf(file, "int operator>(int cmp) { return value > cmp ; }\n") ;
	fprintf(file, "void operator=(CLASS_%s new_value) { value = new_value.value ; }\n", name.string()) ;
	fprintf(file, "int operator==(CLASS_%s cmp) { return value == cmp.value ; }\n", name.string()) ;
	fprintf(file, "int operator!=(CLASS_%s cmp) { return value != cmp.value ; }\n", name.string()) ;
	fprintf(file, "int operator<=(CLASS_%s cmp) { return value <= cmp.value ; }\n", name.string()) ;
	fprintf(file, "int operator>=(CLASS_%s cmp) { return value >= cmp.value ; }\n", name.string()) ;
	fprintf(file, "int operator<(CLASS_%s cmp) { return value < cmp.value ; }\n", name.string()) ;
	fprintf(file, "int operator>(CLASS_%s cmp) { return value > cmp.value ; }\n", name.string()) ;
	fprintf(file, "\tCLASS_%s(int new_value) { value = new_value ; }\n", name.string()) ;
	fprintf(file, "\tCLASS_%s(void) { value = 0 ; }\n", name.string()) ;
	}
{
T_object_class_field *field = fields.first ;
while (field != NULL)
	{
	field->generate_declaration(file) ;
	field = field->next ;
	}
}
if (native_cpp_string != NULL) fprintf(file, "%s", native_cpp_string) ;
if (program->entry == this)
	{
	fprintf(file, "\tint errors_count ;\n") ;
	fprintf(file, "\tCLASS_%s(int argc, const char **argv) ;\n", name.string()) ;
	}
fprintf(file, "\t} ;\n") ;
}

void T_object_class::generate_instance(FILE *file, T_entity_program *program)
{
fprintf(file, "class INTROSPECT_%s : public ", name.string()) ;
if (base_type != NULL) base_type->generate_type_name(file, type_generate_introspect) ;
else fprintf(file, "CLASS_Object_class") ;
fprintf(file, "\n\t{\n") ;
fprintf(file, "public:\n") ;
{
T_object_class_method *method = methods.first ;
while (method != NULL)
	{
	if (method->overloaded) method->generate_virtual_field(file) ;
	method = method->next ;
	}
}
fprintf(file, "\tINTROSPECT_%s(const char *new_name, int generate_fields) ;\n", name.string()) ;
fprintf(file, "\t} ;\n") ;
fprintf(file, "extern INTROSPECT_%s introspect_%s ;\n", name.string(), name.string()) ;
fprintf(file, "class HEADER_%s\n", name.string()) ;
fprintf(file, "\t{\n") ;
fprintf(file, "public:\n") ;
fprintf(file, "\tINTROSPECT_%s *introspect ;\n", name.string()) ;
fprintf(file, "\tCLASS_%s *_previous ;\n", name.string()) ;
fprintf(file, "\tCLASS_%s *_next ;\n", name.string()) ;
fprintf(file, "\tHEADER_%s(void) { introspect = &introspect_%s ; _previous = NULL ; _next = NULL ; }\n", name.string(), name.string()) ;
fprintf(file, "\t} ;\n") ;
fprintf(file, "class INSTANCE_%s\n", name.string()) ;
fprintf(file, "\t{\n") ;
fprintf(file, "public:\n") ;
fprintf(file, "\tHEADER_%s header ;\n", name.string()) ;
fprintf(file, "\tCLASS_%s data ;\n", name.string()) ;
if (enum_class)
	{
	fprintf(file, "void operator=(int new_value) { data.value = new_value ; }\n") ;
	fprintf(file, "void operator=(CLASS_%s new_value) { data.value = new_value.value ; }\n", name.string()) ;
	}
if (program->entry == this)
	{
	fprintf(file, "\tINSTANCE_%s(int argc, const char **argv) : data(argc, argv) {}\n", name.string()) ;
	}
else if (native_cpp_instance_string != NULL)
	{
	fprintf(file, "%s", native_cpp_instance_string) ;
	}
fprintf(file, "\t} ;\n") ;
{
T_constructor *constructor = constructors.first ;
while (constructor != NULL)
	{
	if (constructor->expression != NULL)
		{
		fprintf(file, "extern ") ;
		constructor->generate_prototype(file) ;
		fprintf(file, " ;\n") ;
		}
	constructor = constructor->next ;
	}
}
{
T_object_class_method *method = methods.first ;
while (method != NULL)
	{
	if ((method->expression != NULL) && ((method->base_method == NULL) || (method == search_base_method_use(method->base_method))))
		{
		fprintf(file, "extern ") ;
		method->generate_prototype(file) ;
		fprintf(file, " ;\n") ;
		}
	method = method->next ;
	}
}
}

void T_object_class::generate_definitions(FILE *file, T_entity_program *program)
{
if (program->entry == this)
	{
	fprintf(file, "CLASS_%s::CLASS_%s(int argc, const char **argv)\n", name.string(), name.string()) ;
	fprintf(file, "{\n") ;
	fprintf(file, "errors_count = 0 ;\n") ;
	{
	T_object_class_field *field = fields.first ;
	while (field != NULL)
		{
		if (!field->value_fixed) fprintf(file, "int defined_%s = 0 ;\n", field->name.string()) ;
		field = field->next ;
		}
	}
	fprintf(file, "int count = 1 ;\n") ;
	fprintf(file, "while (count < argc)\n") ;
	fprintf(file, "\t{\n") ;
	{
	int first_field = TRUE ;
	T_object_class_field *field = fields.first ;
	while (field != NULL)
		{
		if (!field->value_fixed)
			{
			if (first_field) first_field = FALSE ;
			else fprintf(file, "else ") ;
			fprintf(file, "\tif (strcmp(argv[count], \"-%s\") == 0)\n", field->name.string()) ;
			fprintf(file, "\t\t{\n") ;
			fprintf(file, "\t\tcount++ ;\n") ;
			fprintf(file, "\t\tif (defined_%s > 0) { fprintf(stderr, \"Argument -%s already defined\\n\") ; errors_count++ ; }\n", field->name.string(), field->name.string()) ;
			field->type->generate_argv(file, field->name) ;
			fprintf(file, "\t\t}\n") ;
			}
		field = field->next ;
		}
	if (!first_field) fprintf(file, "\telse\n") ;
	fprintf(file, "\t\t{\n") ;
	fprintf(file, "\t\tfprintf(stderr, \"Bad argument %%s\\n\", argv[count++]) ;\n") ;
	fprintf(file, "\t\terrors_count++ ;\n") ;
	fprintf(file, "\t\t}\n") ;
	}
	fprintf(file, "\t}\n") ;
	{
	T_object_class_field *field = fields.first ;
	while (field != NULL)
		{
		if (field->default_value == NULL) fprintf(file, "if (defined_%s == 0) { fprintf(stderr, \"Argument -%s not defined.\\n\") ; errors_count++ ; }\n", field->name.string(), field->name.string()) ;
		field = field->next ;
		}
	}
	fprintf(file, "}\n") ;
	}
if (native_cpp_string_body != NULL) fprintf(file, "%s", native_cpp_string_body) ;
{
T_constructor *constructor = constructors.first ;
while (constructor != NULL)
	{
	constructor->generate_method(program, file) ;
	constructor = constructor->next ;
	}
}
{
T_object_class_method *method = methods.first ;
while (method != NULL)
	{
	if ((method->base_method == NULL) || (method == search_base_method_use(method->base_method))) method->generate_method(program, file) ;
	method = method->next ;
	}
}
fprintf(file, "INTROSPECT_%s::INTROSPECT_%s(const char *new_name, int generate_fields)\n", name.string(), name.string()) ;
if (base_type != NULL)
	{
	fprintf(file, " : ") ;
	base_type->generate_type_name(file, type_generate_introspect)  ;
	fprintf(file, "(new_name, FALSE)") ;
	}
else
	{
	fprintf(file, " : CLASS_Object_class(new_name)\n") ;
	}
fprintf(file, "{\n") ;
fprintf(file, "_size = sizeof(INSTANCE_%s) ;\n", name.string()) ;
fprintf(file, "_data_size = sizeof(CLASS_%s) ;\n", name.string()) ;
if (base_type != NULL)
	{
	fprintf(file, "_base_class = &") ;
	base_type->generate_type_name(file, type_generate_introspect_object)  ;
	fprintf(file, " ;\n") ;
	}
else
	{
	fprintf(file, "_base_class = NULL ;\n") ;
	}
fprintf(file, "if (generate_fields)\n") ;
fprintf(file, "\t{\n") ;
T_object_class_field *field = fields.first ;
if (field != NULL)
	{
	fprintf(file, "\tCLASS_%s *ref = NULL ;\n", name.string()) ;
	while (field != NULL)
		{
		fprintf(file, "\t_fields.insert(&(new INSTANCE_Object_class_field(\"%s\", ", field->name.string()) ;
		field->type->generate_type(file) ;
		fprintf(file, ", (char *)&ref->_%s - (char *)ref))->data) ;\n", field->name.string()) ;
		field = field->next ;
		}
	}
fprintf(file, "\t}\n") ;
generate_virtuals(file, this) ;
fprintf(file, "}\n") ;
fprintf(file, "INTROSPECT_%s introspect_%s(\"%s\", TRUE) ;\n", name.string(), name.string(), name.string()) ;
}

void T_object_class::generate_virtuals(FILE *file, T_object_class *ref)
{
if (base_type != NULL) base_type->generate_virtuals(file, ref) ;
T_object_class_method *method = methods.first ;
while (method != NULL)
	{
	if (method->overloaded)
		{
		fprintf(file, "virtual_%s__%s = ", name.string(), method->name.string()) ;
		T_object_class_method *loc = ref->search_overload(method) ;
//fprintf(stderr, "loc=%p\n", loc) ;
		if (loc == NULL)
			{
			fprintf(file, "NULL ;\n") ;
			}
		else
			{
			method->generate_cast(file) ;
			fprintf(file, "_%s__%s ;\n", loc->object_class->name.string(), loc->name.string()) ;
			}
		}
	method = method->next ;
	}
}

// }{--------------------------------------------------------------
